home *** CD-ROM | disk | FTP | other *** search
/ The Programmer Disk / The Programmer Disk (Microforum).iso / xpro / c3 / pro24 / cintr.c < prev    next >
Text File  |  1986-08-06  |  10KB  |  318 lines

  1. /* cintr.c -- code for interrupt management */
  2.  
  3. /*****************************************************************************
  4. *        Change Log
  5. *  Date        | Change
  6. *-----------+-----------------------------------------------------------------
  7. * 31-Dec-85 | Created changelog
  8. * 31-Dec-85 | Add c:\ to include directives
  9. * 31-Dec-85 | Save actual interrupt vector data; don't use constants
  10. *        | (different on PC/AT and PC/XT)
  11. * 31-Dec-85 | Added intr_init
  12. * 31-Dec-85 | Handle secondary interrupt port for AT
  13. * 26-May-86 | Use cmdline.c to get debug switch
  14. *  6-Aug-86 | Modified for Lattice 3.0 -- use "void" to type some routines
  15. *****************************************************************************/
  16. /*
  17.  *    I think this came from Dale Amon, but we had some problems
  18.  *    getting it to work with Lattice C and hacked away to get
  19.  *    something to do the job.  
  20.  */
  21.  
  22. #include "stdio.h"
  23. #include "dos.h"
  24. /* note: dos.h typedefs byte to unsigned char */
  25. /*  cext.h #defines byte to unsigned char     */
  26. #include "cext.h"
  27. #include "cmdline.h"
  28. #include "cintr.h"
  29. #include "atxt.h"
  30.  
  31. /*
  32.  * IBM-XT and IBM-AT interrupt information
  33.  */
  34.  
  35. #define NIRQS 16        /* Maximum number of IRQ levels */
  36.  
  37. short defpc[NIRQS];        /* restore the vector to this PC */
  38. short defseg[NIRQS];        /* and this segment */
  39.  
  40. #define VECTOR(irq)        (0x20 + 4 * (irq))
  41.                     /* Maps interrupt request number
  42.                        to the address of the vector */
  43.  
  44. /*   CAUTION!     CAUTION!   CAUTION!   CAUTION!      CAUTION!   CAUTION!    
  45.      The above "vector" computation DOES NOT WORK for a PC/AT for
  46.      values higher than 7.  IRQ8..15 are vectored starting at 70.
  47.      The proper AT computation, should higher IRQ values be required,
  48.      is 
  49.  
  50.     (0x20 + ((irq) < 8 ? 0x20 + 4*(irq) : 0x70 + 4 * ((irq) - 8)))
  51.  
  52.      but that is much too complicated to want to do in the restricted
  53.      case of having only an IRQ2 device.  But you have now been warned.
  54.  
  55.      Note also that devices which on the PC or XT interrupt on IRQ2 will
  56.      interrupt on the AT at IRQ9, but the software in the BIOS redirects
  57.      this interrupt (PC/AT Tech Ref page 5-71) via the IRQ2 vector.
  58.      
  59.                 *** HOWEVER ***
  60.  
  61.      If the program masks off interrupts by twiddling the mask bit for IRQ2
  62.      it will also mask off the realtime clock interrupt, coprocessor
  63.      interrupt, and *FIXED DISK INTERRUPT*.  Therefore, any attempt to
  64.      manipulate the interrupt masks must be done to the secondary 8259
  65.      controller channel chip, located at locations 0xA0 and 0xA1.
  66.  
  67.      Mask bits in primary mask register:
  68.  
  69.      Bit    XT*            AT**
  70.     7    Printer            Parallel Port 1
  71.     6    Diskette        Diskette controller
  72.     5    Fixed Disk        Parallel Port 2
  73.     4    Serial Port 1        Serial Port 1
  74.     3    Serial Port 2        Serial Port 2
  75.     2    IRQ2            IRQ2 (OR of IRQ8..IRQ15)
  76.     1    Keyboard        Keyboard
  77.     0    Timer            Timer
  78.  
  79.      Mask bits in secondary mask register (AT only)
  80.  
  81.     7                IRQ15
  82.     6                Fixed disk controller
  83.     5                Coprocessor
  84.     4                IRQ12
  85.     3                IRQ11
  86.     2                IRQ10
  87.     1                IRQ9 (Bus IRQ2)
  88.     0                Realtime clock
  89.  
  90.      Source:
  91.  
  92.      * PC/XT Technical Ref page 1-9
  93.      ** PC/AT Technical Ref page 1-11
  94.  
  95. */
  96.  
  97. #define INT_0_CONTROL_PORT    0x20    /* Interrupt chip I/0 port (PC, XT)*/
  98. #define INT_1_CONTROL_PORT    0x21    /*     "      "       "    "      "   */
  99. #define INT2_0_CONTROL_PORT    0xA0    /* Interrupt chip 2 I/O port (AT)  */
  100. #define INT2_1_CONTROL_PORT    0xA1    /*     "      "       "    "      "   */
  101.  
  102. #define EOI(irq)        (0x60 | (irq))
  103.                     /* End of interrupt command to
  104.                        send to PORT1 */
  105.  
  106. #define ndsw 2
  107. private char *dsw[ndsw] = { "-d", "-debug" };
  108.  
  109. int enabled;    /* flag to tell if interrupts are on */
  110. int debug_intr; /* set for debugging */
  111. int IsAT;    /* AT or XT?, initialized here, read-only to others */
  112.  
  113. /****************************************************************************
  114. *    Routines local to this module
  115. ****************************************************************************/
  116. private    void    print_intr();
  117.  
  118. /****************************************************************************
  119. *                   intr_init
  120. * Effect: 
  121. *    Initializes the interrupt routines
  122. ****************************************************************************/
  123.  
  124. void intr_init()
  125. {
  126.     int i;
  127.     debug_intr = (cl_nswitch(dsw, ndsw) != NULL);
  128.     IsAT = (ATXT() == ISAT);
  129.     if (debug_intr) printf("IsAT is %d\n", IsAT);
  130.     for (i = 0; i < NIRQS; i++) defpc[i] = defseg[i] = 0;
  131. }
  132.  
  133. /****************************************************************************
  134. *                  intr_enable
  135. * Inputs:
  136. *    int irq: Interrupt level to enable 
  137. * Effect: 
  138. *    Enables the interrupt in the control port, sets enabled flag true
  139. ****************************************************************************/
  140.  
  141. void intr_enable(irq)
  142.     int irq;
  143. {
  144.     int pv;
  145.  
  146.     if (IsAT && irq == 2) { /* AT on irq2 */
  147.     pv = inp(INT2_1_CONTROL_PORT);
  148.     if (debug_intr)
  149.         printf("intr_enable/AT: (before) %02x = %02x\n",
  150.            INT2_1_CONTROL_PORT, pv);
  151.     pv &= ~(1<<1);
  152.     outp(INT2_1_CONTROL_PORT, pv);
  153.     if (debug_intr) { /* report */
  154.         pv = inp(INT2_1_CONTROL_PORT);
  155.         printf("intr_enable/AT: (after) %02x = %02x\n",
  156.            INT2_1_CONTROL_PORT, pv);
  157.     } /* report */
  158.     } /* AT on irq2 */ else { /* PC or XT or AT not IRQ2 */
  159.     pv = inp(INT_1_CONTROL_PORT);
  160.     pv &= ~(1<<irq);
  161.     outp(INT_1_CONTROL_PORT, pv);
  162.     } /* PC or XT or AT not IRQ2 */
  163.     enabled = true;
  164. }
  165.  
  166. /****************************************************************************
  167. *                 intr_disable
  168. * Inputs:
  169. *    int irq: irq level to disable
  170. * Effect: 
  171. *    Disables the interrupt in the control registers, sets enabled false
  172. ****************************************************************************/
  173.  
  174. void intr_disable(irq)
  175.     int irq;
  176. {
  177.     int pv;
  178.  
  179.     if(IsAT && irq == 2)
  180.        { /* AT    */
  181.      /* On the AT, we mask the interrupt in the secondary register */
  182.      pv = inp(INT2_1_CONTROL_PORT);
  183.      if(debug_intr)
  184.          printf("intr_disable/AT: (before) %02x = %02x\n",INT2_1_CONTROL_PORT,pv);
  185.      pv |= (1<<1);
  186.      outp(INT2_1_CONTROL_PORT,pv);
  187.        } /* AT    */
  188.     else
  189.        { /* PC or XT */
  190.     pv = inp(INT_1_CONTROL_PORT);
  191.     pv |= (1<<irq);
  192.     outp(INT_1_CONTROL_PORT,  pv);
  193.     if(debug_intr)
  194.        { /* report */
  195.         pv = inp(INT2_1_CONTROL_PORT);
  196.         printf("intr_enable/XTAT: (after) %02x = %02x\n",INT2_1_CONTROL_PORT,pv);
  197.        } /* report */
  198.        } /* PC or XT */
  199.     enabled = 0;
  200. }
  201.  
  202. /****************************************************************************
  203. *                 intr_routine
  204. * Inputs:
  205. *    int irq: interrupt level
  206. * Effect: 
  207. *    Set up vector and aintr (assembler code) globals so that
  208. *    the function a_intr is called when an interrupt occurs
  209. * Notes:
  210. *    Possible bug: The segment numbers (esp. ds) may not be correct and 
  211. *    probably should be passed as arguments
  212. ****************************************************************************/
  213.  
  214. int a_irq, a_intr(), a_dsreg;
  215.  
  216. void intr_routine(irq)
  217.     int irq;
  218. {
  219.     struct SREGS s;
  220.  
  221.     segread(&s);
  222.     a_irq = irq;
  223.     intr_set_vector(irq, s.cs, a_intr, 1);
  224.     a_dsreg = s.ds;
  225.     if (debug_intr) printf("cs = %x\tds = %x\n", s.cs,  s.ds);
  226. }
  227.  
  228. /****************************************************************************
  229. *                 intr_cleanup
  230. * Inputs:
  231. *    int irq: irq level to restore interrupt for
  232. * Effect: 
  233. *    Restores the interrupt vector for the irq
  234. ****************************************************************************/
  235.  
  236. void intr_cleanup(irq)
  237.     int irq;
  238. {
  239.     if (defseg[irq] != 0)
  240.     intr_set_vector(irq, defseg[irq], defpc[irq],0);
  241.     if (debug_intr)
  242.     print_intr("After cleanup",irq);
  243. }
  244.  
  245. /****************************************************************************
  246. *                   intr_eoi
  247. * Inputs:
  248. *    int irq: interrupt level to do this to
  249. * Effect: 
  250. *    Sends end of interrupt command to the port for the indicated
  251. *    interrupt level
  252. *
  253. *    On the AT, the IRQ2 interrupt really came in on vector 71, but
  254. *    EOI has been sent to the secondary I/O port and the interrupt has
  255. *    been revectored to 0A.    See BIOS listing for the AT page 5-71.
  256. ****************************************************************************/
  257.  
  258. void intr_eoi(irq)
  259.     int irq;
  260. {
  261.     outp(INT_0_CONTROL_PORT, EOI(irq));
  262. }
  263.  
  264. /****************************************************************************
  265. *                intr_set_vector
  266. * Inputs:
  267. *    int irq: interrupt vector level to set
  268. *    short seg: segment value to store in interrupt level
  269. *    short pc:  pc value to store in interrupt level
  270. *    boolean save: true to save the old value, false to just overwrite
  271. *            it
  272. * Effect: 
  273. *    Sets the interrupt vector cs:ip to the indicated values
  274. ****************************************************************************/
  275.  
  276. void intr_set_vector(irq, seg, pc, save)
  277.     int irq;
  278.     short seg;
  279.     short pc;
  280.     int save;
  281. {
  282.     short s[2];
  283.     short o[2];
  284.  
  285.     s[0] = pc;
  286.     s[1] = seg;
  287.     if (debug_intr)
  288.     print_intr("Before poking new vector",irq);    
  289.     peek(0, VECTOR(irq), (char *) o, sizeof(o));
  290.     poke(0, VECTOR(irq), (char *) s, sizeof(s));
  291.     if (save) { /* save vector */
  292.     defseg[irq] = o[1];
  293.     defpc[irq] = o[0];
  294.     } /* save vector */
  295.     if (debug_intr) print_intr("After poking new vector",irq);    
  296. }
  297.  
  298. /****************************************************************************
  299. *                  print_intr
  300. * Inputs:
  301. *    char * msg: Identifying message
  302. *    int irq: Interrupt to print
  303. * Effect: 
  304. *    Prints the contents of the interrupt vector
  305. ****************************************************************************/
  306.  
  307. private void print_intr(msg,irq)
  308.     char * msg;
  309.     int irq;
  310. {
  311.     short s[2];
  312.  
  313.     peek(0, VECTOR(irq), (char *) s, sizeof(s));
  314.     printf(
  315.     "%s: vector %d, address %x, pc = %x, seg = %x, defpc=%x, defseg=%x\n",
  316.     msg, irq, VECTOR(irq), s[0], s[1],defpc[irq],defseg[irq]);
  317. }
  318.